/**
 * SimData 
 *
 * Manages map methods and data. Public methods are returned.
 *
 * @param Object map Google map object
 */
var SimData = function(map) {
	var map = map;
	var mapbounds;
	var allShapes = [];
	var allPolylines = [];
	var startpoints = [];
	var endpoints = [];
	var infowindows = [];
	var findPathURI = "/findpath/";

	/**
	 * Return latitude and longitude coordinates on mouse move
	 */
	function getCoords() {
		google.maps.event.addListener(map, 'mouseover', function(e) {
			console.log(e.latLng);
		});
	}

	function getbounds(map) {
		console.log(map);
	}

	function saveState() {
		$.cookie("startpoints", JSON.stringify(startpoints));
		$.cookie("endpoints", JSON.stringify(endpoints));
	}

	/**
	 * Remove marker from polyline and polygon. Update path and marker arrays.
	 * 
	 * @param Object params Path and marker arrays
	 */
	function removePolyMarker(params) {
		params.marker.setMap(null);
		for (var i = 0, I = params.markers.length; i < I && params.markers[i] != params.marker; ++i);
		params.markers.splice(i, 1);
		params.path.removeAt(i);
		params.payload.splice(i,1);
		// Save shape
		$.cookie('allShapes', JSON.stringify(allShapes)); 
	}

	/**
	 * Create start/end point markers
	 * StyledMarker is from the google-maps-utility library
	 *
	 * @param Object options Object containing position, animation
 	 */
	function placeMarker(options) {
		var styledMarker = new StyledMarker({
			styleIcon: new StyledIcon(
				StyledIconTypes.BUBBLE, {
					color: options.color,
					text: options.text
				}),
			position: options.position,
			map: map,
			draggable: true
		});

		// Push marker to appropriate array (start or endpoint)
		if (options.type === 'start') {
			pushMarker(startpoints, 'startpoints');
			moveMarker(startpoints);
		} else {
			pushMarker(endpoints, 'endpoints');
			moveMarker(endpoints);
		}	

		function pushMarker(markers, markerType) {
			//update our global list of startpoints
			markers.push({
				lat: options.position.lat(),
				lng: options.position.lng() 
			});
			
			// Set parameters for removeMarker (scoping problems)
			var params = {
				marker: styledMarker,
				currentpos: options.position,
				markers: markers,
				type: markerType
			}; 
			// On marker click, remove it current marker and update startpoints list
			google.maps.event.addListener(styledMarker, 'rightclick', function() { 
				removeMarker(params);
				// Save both marker types
				saveState();
			});
		}

		/**
		 * Update marker array with new marker position (on marker drag)
		 */
		function moveMarker(markers) {
			google.maps.event.addListener(styledMarker, 'dragstart', function() {
				var startpos = styledMarker.getPosition();

				google.maps.event.addListener(styledMarker, 'dragend', function() {
					for (var i = 0; i < markers.length; i++) {
						var lat = markers[i].lat;
						var lng = markers[i].lng;

						if (lat === startpos.lat() && lng === startpos.lng()) {
							markers[i].lat = styledMarker.getPosition().lat();	
							markers[i].lng = styledMarker.getPosition().lng();	
						}
					}
					// Save both marker types
					saveState();
				});
			});
		}
	}

	/**
	 * Remove a marker from the map/ and startpoints or endpoints arrays
	 * 
	 * @param Object param Clicked marker, marker array, clicked position
	 */
	function removeMarker(params) {
		params.marker.setMap(null); 
		for (var i = 0; i < params.markers.length; i++) {
			// Compare our array of starting points with the marker that was clicked on,
			// if they are the same, then remove that item from the array.
			var lat = params.markers[i].lat;
			var lng = params.markers[i].lng;
			
			if (lat === params.currentpos.lat() && lng === params.currentpos.lng()) {
				params.markers.splice(i, 1);
				//$.cookie(params.type, JSON.stringify(params.markers));
			}	
		}
	}

	/**
	 * Public methods
	 */
	var publicMethods = {
		 
		placePolyline: function(params, polyline, markers) {
			var path = polyline.getPath();
			//path.push(event.latLng);
			path.push(params.position);

			var marker = new StyledMarker({
				styleIcon: new StyledIcon(
					StyledIconTypes.MARKER, {
						//color:"AED6EC"
						color:"2d2d2d"
					}),
				//position: event.latLng,
				position: params.position,
				map: map,
				title: '#' + path.getLength(),
				draggable: true
			});

			//markerlatLng.push({
			//coords.push({
				//lat: event.latLng.lat(),
				//lng: event.latLng.lng()
				//lat: params.position.lat(),
				//lng: params.position.lng()
			//});
			
			//markerlatLng.push(event.latLng);
			markers.push(marker);
		
			// Parameters for the removePolyMarker callback
			//var params = { marker: marker, markers: markers, payload: markerlatLng, path: path };
			/*
			var params = { marker: marker, markers: markers, payload: coords, path: path };
			google.maps.event.addListener(marker, 'rightclick', function() {
				removePolyMarker(params);

				for (var i = 0; i < allPolylines.length; i++) {
					if (allPolylines[i][0].length === 0) {
						allPolylines.splice(i,1);
					}
				}
			});
			*/

			// Save shape
			//$.cookie('allShapes', JSON.stringify(allShapes)); 
			google.maps.event.addListener(marker, 'dragstart', function() {
				var startpos = marker.getPosition();

				google.maps.event.addListener(marker, 'dragend', function() {
					for (var i = 0, I = markers.length; i < I && markers[i] != marker; ++i);
					path.setAt(i, marker.getPosition());

						/*
					for (var i = 0; i < allPolylines.length; i++) {
						var currentShape = allPolylines[i].coords;
						var currentShapeLength = allPolylines[i].coords.length;
						for (var j = 0; j < currentShapeLength; j++){
							var lat = currentShape[j].lat;
							var lng = currentShape[j].lng;

							if (lat === startpos.lat() && lng === startpos.lng()) {
								allPolylines[i].coords[j].lat = marker.getPosition().lat();	
								allPolylines[i].coords[j].lng = marker.getPosition().lng();	
							}
						}
					}
						*/
					// Save shape
					//$.cookie('allShapes', JSON.stringify(allShapes)); 
				});
			});

			return marker;
		},

		/**
		 * Draw polyline
		 * Paths in each polyline are appened to markerlatLng, each polyline is 
		 * pushed to allPolylines
		 */
		drawPolyline: function(params) {
			//var markers = [];

			polyline = new google.maps.Polyline(params.polyLineOptions);
			polyline.setMap(map);

			//Declare markerlatLng array to store the current polylines paths
			//var markerlatLng = [];
			var coords = [];

			//Add the current polyline to the allPolylines property
			//allPolylines.push(markerlatLng);
			allPolylines.push({
				coords: coords
			});

			console.log(allPolylines);

			return polyline;
		},

		/**
		 * Draw polygon
		 * Creates polylines that can be closed into a polygon
		 *
		 * @param Object params Contains polygon options object, polygon type (building, obstruction, etc)
		 */
		drawShape: function(params) { 
			var path = new google.maps.MVCArray;
			var poly = new google.maps.Polygon(params.polyoptions);

			poly.setMap(map);
			poly.setPaths(new google.maps.MVCArray([path]));

			//Declare array to store the current lat/lngs
			coords = [];

			//Add the current polygon to the allShapes property
			allShapes.push({
				coords: coords,
				type: params.type
			});

			google.maps.event.addListener(poly, 'click', function(event) {
				var message = prompt("Set message");
				var infowindow = new google.maps.InfoWindow({
					content: message
				});

				infowindows.push({
					content: message,
					lat: event.latLng.lat(),
					lng: event.latLng.lng()
				});


				infowindow.setPosition(event.latLng);
				infowindow.open(map);
			});

			//$.cookie('infowindows', JSON.stringify(infowindows));

			return path;
		},

			//var label = typeof(label) != 'undefined' ? false : label;
			//google.maps.event.addListener(map, 'click', function(event) {
			//path.insertAt(path.length, event.latLng);
			
		placeShapePath: function(params, path, markers) {
			path.insertAt(path.length, params.position);
			var marker = new google.maps.Marker({
			//	position: event.latLng,
				position: params.position,
				map: map,
				draggable: true
			});

			markers.push(marker);
			marker.setTitle("#" + path.length);

			coords.push({
				//lat: event.latLng.lat(),
				//lng: event.latLng.lng()
				lat: params.position.lat(),
				lng: params.position.lng()
			});

			// Save shape
			$.cookie('allShapes', JSON.stringify(allShapes)); 

			// Click on a marker to remove that point
			// We have to send all of this data to the remove function due to scoping
			var params = { marker: marker, markers: markers, payload: coords, path: path };
			google.maps.event.addListener(marker, 'rightclick', function() {
				removePolyMarker(params);

				for (var i = 0; i < allShapes.length; i++) {
					if (allShapes[i].coords.length === 0) {
						allShapes.splice(i,1);
					}
				}
			});

			google.maps.event.addListener(marker, 'dragstart', function() {
				var startpos = marker.getPosition();

				google.maps.event.addListener(marker, 'dragend', function() {
					for (var i = 0, I = markers.length; i < I && markers[i] != marker; ++i);
					path.setAt(i, marker.getPosition());

					/**
					 * This is really messy at the moment, but works
					 *
					 * First, cycle through all of the shapes
					 * Second, loop through the current shape and see if the
					 * lat,lng matches the startposition (startpos) lat,lng.
					 * If those are equal, then update the item.
					 */
					for (var i = 0; i < allShapes.length; i++) {
						var currentShape = allShapes[i].coords;
						var currentShapeLength = allShapes[i].coords.length;

						for (var j = 0; j < currentShapeLength; j++){
							var lat = currentShape[j].lat;
							var lng = currentShape[j].lng;

							if (lat === startpos.lat() && lng === startpos.lng()) {
								allShapes[i].coords[j].lat = marker.getPosition().lat();	
								allShapes[i].coords[j].lng = marker.getPosition().lng();	
							}
						}
					}
					// Save shape
					$.cookie('allShapes', JSON.stringify(allShapes)); 
				});
			});
			//});	
		},

		/**
		 * Directions request
		 *
		 * @param Object position Object containing origin and destination latLng objects
		 */
		directions: function(position) {
			var directionsService = new google.maps.DirectionsService();
			var directionsDisplay = new google.maps.DirectionsRenderer();

			directionsDisplay.setMap(map);

			var request = {
				origin: position.origin, 
				destination: position.dest,
				travelMode: google.maps.DirectionsTravelMode.DRIVING
			};

			directionsService.route(request, function(response, status) {
				if (status == google.maps.DirectionsStatus.OK) {

					console.log(response.routes[0].legs[0].distance.value);
					console.log(response.routes[0].legs[0].duration.value);

					directionsDisplay.setDirections(response);
				}
			});
		},

		/**
		 * placemarker
		 * Used to place markers for start and exit markers
		 *
		 * @param Object options Color, text, and position of marker
		 */
		placeMarker: function(options) { 
			placeMarker(options);
		},

		getShapes: function() {
			return allShapes;
		},

		getPolylines: function() {
			return allPolylines;
		},

		getEndpoints: function() {
			return endpoints;
		},

		getStartpoints: function() {
			return startpoints;
		},

		saveState: function() {
			saveState();
		},

		getInfoWindows: function() {
			console.log(infowindows);
		},

		sendOverlays: function() {
			var mapbounds = {
				northeast: map.getBounds().getNorthEast(),
				southwest: map.getBounds().getSouthWest()
			};

			var data = {
				startpoints: startpoints,
				endpoints: endpoints,
				shapes: allShapes,
				polylines: allPolylines,
				mapbounds: mapbounds
			};

			$.ajax({
				type: 'POST',
				url: findPathURI,
				data: JSON.stringify(data),
				success: function(data) {
					console.log('returned from view');
					console.log(data);
				}
			});
		},

		getPolygonsTest: function() {
			polygons.forEach(function(item) {
				path = item.getPath();
				for (var i = 0; i < path.length; i++) {
					var coords = path.getAt(i);
					console.log('lat'+ coords.lat() + 'lng' + coords.lng());
				}
			});
		},

		getCoords: function() {
			getCoords();
		}
	};

	// Return object to make methods available
	return publicMethods;
};
